﻿using System;
using System.Net.NetworkInformation;
using ContosoDashboard.ContosoDashboardService;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace ContosoDashboard
{
    public class ReactiveContosoService
    {
        private readonly ObservableCollection<CustomerInfo> _clients;
        private readonly ContosoServiceObservable _observable;

        private static readonly ReactiveContosoService _instance = new ReactiveContosoService();

        private class ContosoServiceObservable : IObservable<SendUpdateReceivedEventArgs>, IDisposable
        {
            private ContosoServiceClient _client;
            private readonly List<IObserver<SendUpdateReceivedEventArgs>> _observers;

            public ContosoServiceObservable()
            {
                _observers = new List<IObserver<SendUpdateReceivedEventArgs>>();

#if DEBUG
                OnNetworkAvailable();
#else
                if (NetworkInterface.GetIsNetworkAvailable())
                    OnNetworkAvailable();
#endif
                NetworkChange.NetworkAddressChanged += NetworkChangeNetworkAddressChanged;
            }

            private void NetworkChangeNetworkAddressChanged(object sender, EventArgs e)
            {
                if (NetworkInterface.GetIsNetworkAvailable())
                    OnNetworkAvailable();
                else
                    OnNetworkUnavailable();
            }

            private void OnNetworkAvailable()
            {
                if (_client == null)
                {
                    _client = new ContosoServiceClient();
                    _client.SubscribeCompleted += ClientSubscribeCompleted;
                    _client.SubscribeAsync();
                }
            }

            private void ClientSubscribeCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
            {
                _client.SubscribeCompleted -= ClientSubscribeCompleted;
                _client.SendUpdateReceived += ClientSendUpdateReceived;
            }

            private void ClientSendUpdateReceived(object sender, SendUpdateReceivedEventArgs e)
            {
                foreach (var observer in _observers)
                    observer.OnNext(e);
            }

            private void OnNetworkUnavailable()
            {
                if (_client != null)
                {
                    _client.CloseAsync();
                    _client = null;
                }
            }

            public IDisposable Subscribe(IObserver<SendUpdateReceivedEventArgs> observer)
            {
                _observers.Add(observer);

                return this;
            }

            public void Dispose()
            {
                _client.CloseAsync();
                foreach (var observer in _observers)
                    observer.OnCompleted();
            }
        }

        public ObservableCollection<CustomerInfo> Customers
        {
            get
            {
                return _clients;
            }
        }

        public static ReactiveContosoService Current
        {
            get { return _instance; }
        }

        protected ReactiveContosoService()
        {
            _observable = new ContosoServiceObservable();
            _clients = new ObservableCollection<CustomerInfo>();
            _observable.Subscribe(it => _clients.Insert(0, it.Customer));
        }

        internal void Close()
        {
            _observable.Dispose();
        }
    }
}
